\section{编译过程}
通常的程序需要经过预处理阶段，编译阶段，汇编阶段,链接阶段。 
\begin{itemize}
%\item 预处理阶段：预处理阶段对包含源代码的文本文件（test.cc）处理，比如包含头文件到文件中，替换宏定义。生成预处理后的文件test.i。
\item 编译阶段：编译器将预处理生成的文件翻译成汇编程序(test.s)，汇编语言程序中的每条语句都以一种标准的文本格式确切的描述一条低级机器语言指令。汇编语言能为不同高级语言的不同编译器提供通用的输出语言。 
\item 汇编阶段：汇编器as将test.s翻译成机器语言，把这些指令打包成一种可重定位的目标程序格式，将结果保存在目标文件test.o中。 
\item 链接阶段:再test.cc 程序中调用了系统函数cout，链接器将改函数的目标文件cout.o 合并到test.o程序中生成可执行的目标程序。 
\end{itemize}
\begin{figure}[!ht]
	\centering
	\includegraphics[width=\textwidth]{compile.png}
	\caption{编译过程}
\end{figure}
\subsection{库文件}
静态链接库:静态链接库是obj文件的一个集合，扩展名为.a。静态链接库由程序ar生成，可以再不用重新编译程序库代码的情况下，进行程序的重新链接，这种方法节省了编译过程的时间。静态库的另一个优势是开发者可以提供库文件给使用人员不用开放源代码。理论上静态库比动态库速度快1\%-5\%.
\begin{bash}
# 生成`add.o`文件
clang++ -c add.cc
# 生成`libadd.a`静态链接库
ar -rcs libadd.a add.o
# 生成二进制文件
clang++ -o t main.cc libadd.a
# 或者在系统目录下查找静态链接库参数不包含静态链接库`libadd.a`的`lib`和`.a`
clang++ -o t main.cc -ladd
# 如果在指定目录查找需要使用
clang++ -o t main.cc -L./ -l add
\end{bash}
动态库是程序运行时加载的库，当动态库正确安装后，所有的程序都可以使用动态库运行程序。动态链接库是目标文件的集合，目标文件在动态库中的组织方式是按照特殊方式形成的。库中函数和变量的地址是相对地址，不是绝对地址，真实地址在调用动态库的程序加载时形成。

动态库的名称有别名(soname),真名(realname)和链接名(linker name)。别名由一个前缀lib，然后是库的名字加上.so构成。真名是动态库的真实名称，一般总是在别名的基础上加上一个小的版本号，发布版本构成。除此之外，还有一个链接名，即程序链接时使用的库的名字。在动态链接库安装的时候总是复制库文件到某个目录，然后用软连接生成别名，在库文件进行更新的时候仅仅更新软连接即可。\\*
\bashinline{clang++ -shared -Wl,-soname,libadd.so -o libstr.so.1 add.cc}
\begin{itemize}
\item shared:生成动态链接库
\item -soname:生成动态链接库的别名libadd.so
\item 实际的动态链接库libstr.so.1
\end{itemize}
动态连接库不能随意使用，要在运行的程序中使用动态链接库需要指定系统的动态链接库搜索路径，让系统找到运行所需要的动态链接库才可以。系统中的配置文件/etc/ld.so.config是动态链接库的搜索路径配置文件。在这个文件里放置了可以被linux共享的动态链接库所在的目录的名字。内容如下:
\begin{Textcode}
include /etc/ld.so.conf.d/*.conf 
\end{Textcode}
包含了动态库相关的配置文件，而这些文件又存储在/etc/ld.so.conf.d/目录下:
\begin{Textcode}
├── android-sdk.conf
├── i386-linux-gnu.conf
├── libc.conf
├── opencv.conf
├── x86_64-linux-gnu.conf
├── x86_64-linux-gnu_EGL.conf -> /etc/alternatives/x86_64-linux-gnu_egl_conf
└── x86_64-linux-gnu_GL.conf -> /etc/alternatives/x86_64-linux-gnu_gl_conf
\end{Textcode}
为了让添加的动态链接库能被系统共享需要运行ldconfig。ldconfig命令的作用是在系统的\textcolor{red}{默认搜索路径}和\textcolor{red}{动态链接库配置文件中列出的目录}里搜索动态链接库，创建动态链接装入程序需要的链接和缓存文件。搜索完毕后将结果写入缓存文件/etc/ld.so.cache。ldconfig命令在/sbin目录下，如果终端提示没有找到ldconfig将/sbin添加到环境变量中即可。
\subsection{gcc常用的选项及含义}
\begin{itemize}
\item -Idir:将头文件的搜索路径扩大，包含dir目录
\item -Ldir:将链接时使用的链接库搜索路径扩大，包含dir目录。gcc会优先使用共享程序库。
\item -static：仅选用静态程序库进行链接，如果一个目录中静态库和动态库都存在，则仅选用静态库。
\item -On：优化程序，程序优化后执行速度会更快，程序占用空间会更小。通常gcc会进行很小的优化，优化的级别可选，即n。通常的优化级别是2.
\item -Wall:打开所有gcc能够提供的，常用的警告信息。
\end{itemize}

% \begin{table}[!ht]
% \centering
% \begin{tabular}{ |m{3cm}||m{3cm}|m{3cm}|  }
%  \hline
%  \multicolumn{3}{|c|}{融合四个单元格为一个单元格} \\
%  \hline
%  第二行第一列& 第二行第二列 &第二行第三列\\
%  \hline
%  第三行第一列   & 第三行第二列&第三行第三\\
%  第四行第一列   & 第四行第二列&第四行第四\\
%  第五行第一列   & 第五行第二列&第五行第五\\
%  \hline
% \end{tabular}
% \end{table}

多工程文件的编译。下面的例子中函数实现了两个数的加减操作
\cppfile{cxxcode/mult_cc/ex1/add.hpp}
\cppfile{cxxcode/mult_cc/ex1/sub.hpp}
这两个头文件包含了定义在外部的函数原型。\\
下面的代码包含了int和double求和的函数定义
\cppfile{cxxcode/mult_cc/ex1/add_int.cc}
\cppfile{cxxcode/mult_cc/ex1/add_double.cc}

下面的代码包含了int和double求差的函数定义
\cppfile{cxxcode/mult_cc/ex1/sub_int.cc}
\cppfile{cxxcode/mult_cc/ex1/sub_double.cc}
主函数如下:
\cppfile{cxxcode/mult_cc/ex1/main.cc}
编译命令:\cppinline{clang++ -o t add_int.cc add_double.cc sub_int.cc sub_double.cc main.cc}
使用Makefile文件编译:
\makefile{cxxcode/mult_cc/ex1/Makefile}
\subsection{Makefile中自定义变量}
使用Makefile进行规则定义的时候，用户可以定义自己的变量，称为用户自定义变量。
例如:\makeinline{OBJS = add_int.o add_double.o sub_int.o sub_double.o main.o}，调用OBJS的时候前面加上\$即可。
\begin{make}
t:
    gcc -o t $(OBJS)
\end{make}
\begin{make}
CC = gcc
TARGET = t
RM = rm -rf
OBJS = add_int.o add_double.o sub_int.o sub_double.o main.o
$(TARGET):$(OBJS)
    $(CC) -o $(TARGET) $(OBJS) 
# %o:%c表示将OBJS中的.o文件替换为.cc文件
$(OBJS):%s.o%.cc
# $<表示依赖结果main.cc,$@TARGET域的名称，即main.o
    $(CC) -c $< -o $@
clean:
    -$(RM) $(TARGET) $(OBJS)
\end{make}
\begin{table}
\centering
\begin{tabular}{ccc}
\toprule
变量名&含义&默认值\\
\midrule
AR&生成静态库库文件的程序名称&ar\\
AS&汇编编译器名称&as\\
CC&C语言编译器的名称&cc\\
CPP&C语言与编译器的名称&\$(CC) -E\\
CXX&C++语言编译器的名称&g++\\
FC&FORTRAN语言编译器的名称&f77\\
RM&删除文件程序的名称&rm -f\\
ARFLAGS&生成静态库文件程序的选项&无默认值\\
ASFLAGS&汇编语言编译器的编译选项&无默认值\\
CLAGS&C语言编译的编译选项&无默认值\\
CPPFLAGS&C语言预编译的编译选项&无默认值\\
CXXFLAGS&C++语言编译的编译选项&无默认值\\
FFLAGS&FORTRAN语言编译器的编译选项&无默认值\\
\bottomrule
\end{tabular}
\end{table}
\subsection{Makefile中的自动变量}
Makefile文件中的编译语句中经常会出现目标文件和依赖文件，自动变量代表这些目标文件和依赖文件。
\begin{table}[!ht]
\caption{Makefile文件中常见的自动变量和含义}
\centering
\begin{tabular}{m{2cm}m{10cm}}
\toprule
变量&含义\\
\midrule
\$*&表示目标文件的名称，不包含目标文件的扩展名\\
\$+&表示所有的依赖文件，这些依赖文件之间以空格分开，按照出现的先后顺序，其中可能包含重复的依赖文件\\
\$<&表示依赖项中第一个依赖文件的名称\\
\$?&依赖项中，所有目标文件时间戳的依赖文件，依赖文件之间以空格分开\\
\$@&目标项中目标文件的名称\\
\${}\^&依赖项中，所有不重复的依赖文件，这些文件之间以空格分开\\
\bottomrule
\end{tabular}
\end{table}
VPATH变量能帮助make自动找到指定文件的目录并添加到文件上，使用方法如下:\\
\makeinline{VPATH=path1:path2}
\subsection{递归make}
make命令有递归调用的作用，他可以递归调用每个子目录中的Makefile文件。例如，在当前目录
下有一个Makefile,而目录add（假设存放add\_int.cc）,sub(假设存放sub\_duble.cc)及主控
文件main.cc有不同的人维护，可以用如下的方式编译add中的文件:
\begin{make}
add:
    cd add && $(MAKE)
\end{make}
它等价于:
\begin{make}
add:
    $(MAKE) -C add
\end{make}
上面两个粒子的意思都是先进入子目录下的add中然后执行make命令。

调用\makeinline{"$(MAKE) -C"}的Makefile叫做总控Makefile。如果总控Makefile中的一些变量需要传递给下层
的Makefile，可以使用export命令，例如需要想下层的Makefile传递目标文件的导出路径:\\
\makeinline{export OBJSDIR=./objs}

如上面

